/*
 * Copyright 2002-2008 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.easyioc.config;

import java.io.File;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.apache.commons.configuration.CompositeConfiguration;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;

import com.easyioc.ResourceProcessException;

/**
 * Load configuration information from Properties files.
 * 
 * @author Ali Yang
 * 
 */
public class PropertiesConfigurationReader implements ConfigurationReader {
	private static PropertiesConfigurationReader instance;
	
	private PropertiesConfigurationReader() {
		
	}
	
	public static PropertiesConfigurationReader getInstance() {
		if (instance == null) {
			instance = new PropertiesConfigurationReader();
		}
		return instance;
	}

	@Override
	public BeanDefinition[] read(Collection<File> configFiles) {
		CompositeConfiguration cc = new CompositeConfiguration();
		for (File configFile : configFiles) {
			try {
				cc.addConfiguration(new PropertiesConfiguration(configFile));
			} catch (ConfigurationException e) {
				throw new ResourceProcessException(
						"Error occur when process the Properties file + [ "
								+ configFile + " ].", e);
			}
		}

		Map<String, BeanDefinition> beanDefMap = new HashMap<String, BeanDefinition>();
		simpleProcess(beanDefMap, cc);
		addProps(beanDefMap, cc);

		return beanDefMap.values().toArray(new BeanDefinition[beanDefMap.values().size()]);
	}

	/*
	 * Add the beanName and className info into BeanDefinition instances.
	 */
	@SuppressWarnings("unchecked")
	private void simpleProcess(Map<String, BeanDefinition> beanDefMap,
			Configuration conf) {
		Iterator<String> iter = conf.getKeys();
		while (iter.hasNext()) {
			String key = iter.next();
			if (!isPropDefKey(key)) {
				BeanDefinition bd = new BeanDefinition(key, conf.getString(key));
				beanDefMap.put(key, bd);
			}
		}
	}

	/*
	 * Add property infos into BeanDefinition instances.
	 */
	@SuppressWarnings("unchecked")
	private void addProps(Map<String, BeanDefinition> beanDefMap,
			Configuration conf) {
		Iterator<String> iter = conf.getKeys();
		while (iter.hasNext()) {
			String key = iter.next();
			if (isPropDefKey(key)) {
				BeanDefinition bd = beanDefMap.get(key.substring(0, key
						.indexOf(".")));
				if (bd == null) {
					throw new com.easyioc.config.ConfigurationException(
							"BeanDefinition with the beanName [ " + key
									+ " ] can not be found.");
				}
				// Config "bean1.prop1" the propName should be "prop1"
				String propName = key.substring(key.indexOf(".") + 1);
				bd.addPropDef(propName, conf.getString(key));
			}
		}
	}

	/*
	 * Whether a properties key is a bean definition or a prop definition.
	 */
	private boolean isPropDefKey(String key) {
		return key.indexOf(".") > -1;
	}
}
